#include "SocketPool.h"

#define LOGGER_NAME "shadow.sscf.socketpool"

#include <iostream>

using std::cout;
using std::endl;

SocketPool::SocketPool() {
	_logger = log4cxx::Logger::getLogger(LOGGER_NAME);
}

SocketPool::~SocketPool() {}

int SocketPool::init(int pool_num, const char *ip, int port, int conn_timeout_in_sec) {
		if (NULL == ip || port < 0) {
				LOG4CXX_ERROR(_logger, "socket pool init error, invalid ip or port, port:" << port);
				return -1;
		}
		int res = _res_pool.init(pool_num, -1);
		if (res < 0) return -2;
		for (int i = 0; i < pool_num; i++) {
				SSocket s;
				s.set_index(i);
				_sockets.push_back(s);
		}
		_dst_ip = ip;
		_dst_port = port;
		_conn_timeout_in_sec = conn_timeout_in_sec;
		LOG4CXX_INFO(_logger, "socket pool, init ok, dst_ip:" << _dst_ip << ", dst_port:" << _dst_port << ", pool_num:" << \
						pool_num << ", conn_timeout_in_sec:" << _conn_timeout_in_sec);
		return 1;
}


SSocket * SocketPool::acquire_socket() {
//		while (true) {
				int res, s_error;
				int index = _res_pool.acquire_resource();
				if (index < 0) {
						LOG4CXX_ERROR(_logger, "can not acquire socket from pool, all sockets are in use, dst_ip:" << \
										_dst_ip << ", dst_port:" << _dst_port << ", pool_size:" << \
										_res_pool.get_pool_size() << ", conn_timeout_in_sec:" << _conn_timeout_in_sec);
						return NULL;
				}
				SSocket & s = _sockets[index];
				if (!s.is_connected() || (-1 != s.get_last_recv_fail_time()) || (-1 != s.get_last_send_fail_time()) || \
								(res = s.get_sock_opt_error(s_error) < 0) || 0 != s_error){
						res = reconnect_socket_resource(s);
						if (res < 0) {
								_res_pool.release_resource(index);
								return NULL;
						}
				}
				return &_sockets[index];
//		}
}

int SocketPool::release_socket(SSocket * s) {
		if (NULL == s) {
				LOG4CXX_ERROR(_logger, "release socket to resoure pool error, NULL socket");
				return -1;
		}
		int index = s->get_index();
		_res_pool.release_resource(index);
		return 1;
}

int SocketPool::reconnect_socket_resource(SSocket & s) {
		if (s.is_connected()) s.close();
		int res = s.connect(_dst_ip.c_str(), _dst_port, _conn_timeout_in_sec); 
		if (res < 0) {
				LOG4CXX_ERROR(_logger, "can not reconnect socket, index:" << s.get_index() << ", res:" << res);
				return -1;
		}
		LOG4CXX_INFO(_logger, "reconnect socket resource ok, index:" << s.get_index() << ", ip:" << _dst_ip << \
						", port:" << _dst_port);
		return 1;
}
